#include "StdAfx.h"
#include "DataElement.h"
#include <sstream>
#include <iomanip>
#include <algorithm>
const blocktype ibFUNC = blocktype(0x01,0x03);

/************************************************************************/
/*  BufferData_ParserBase                                               */
/************************************************************************/
/* I do not care whether the pOut exceeds the boundary of buffer.
 *	it's the caller's responsibility
 */
void BufferData_ParserBase ::ParseData(const char* IN pBase, unsigned int IN offset, 
									unsigned int IN length,  char* OUT pOUT)
{
	memcpy(pOUT, (unsigned char*)pBase + offset,length);
}


/************************************************************************/
/*  FuncData_ParserBase                                                 */
/************************************************************************/
FuncData_ParserBase::FuncData_ParserBase()
{
}

FuncData_ParserBase::~FuncData_ParserBase()
{
}

/*[blk header]
 *01 00 00 00  03 00 00 00  00 00 00 00  01 00 00 00
 *
 *[IN_buffer, pBase]
 *4D 01 00 00  05 02 00 00  ............
 *
 *[OUT_buffer, pBase]
 *44 01 00 00  05 02 00 00 	............
 */
void FuncData_ParserBase ::ParseFuncParam(const char* IN pBase, unsigned int IN theIndex, 
										char* OUT pValue, unsigned int& INOUT nlength)
{
	// 1. find the param count  [5/7/2013 Pseudonym]
	unsigned int nParamCount = 0;
	ParseData(pBase, PARAMCOUNT_OFFSET, 1, (char*)&nParamCount);// only One byte is used to store param cnt  [5/9/2014 pseudonym]
	if(nParamCount== 0)
	{
		nlength = 0;
		return;
	}

	if(theIndex >= nParamCount)
	{
		nlength = 0;
		return;
	}

	// 2. find the param offset value [5/7/2013 Pseudonym]
	unsigned short nParamSubOffset = 0;
	ParseData(pBase, PARAMBLK_OFFSET + 16*theIndex + 1, 2, (char*)&nParamSubOffset);

	unsigned int nParamLength = 0;
	ParseData(pBase, PARAMBLK_OFFSET + 16*theIndex + 12, 4, (char*)&nParamLength);

	// 3. find the param value based on the index [5/7/2013 Pseudonym]
	if(nlength < nParamLength)
	{
		nlength = 0;
		return;
	}

	nlength = nParamLength;
	ParseData(pBase, PARAMBLK_OFFSET + nParamCount * 16 + nParamSubOffset, nParamLength, pValue);

	return;
}

/************************************************************************/
/* general_InOutBuffer_parser                                           */
/************************************************************************/
general_InOutBuffer_parser::general_InOutBuffer_parser()
{

}
general_InOutBuffer_parser::~general_InOutBuffer_parser()
{

}
int general_InOutBuffer_parser::MoveToEnd(const char* IN pStart, char*& INOUT pEnd)
{
	unsigned int nBufLength = (unsigned char*)pEnd - (unsigned char*)pStart;
	// 1. find the param count [5/8/2013 Pseudonym]
	if(nBufLength < PARAMBLK_OFFSET)
		return RETURN_STATUS::RETURN_NEEDMOREDATA;

	unsigned int nParamCount = 0;
	ParseData(pStart, PARAMCOUNT_OFFSET, 1, (char*)&nParamCount);// only One byte is used to store param cnt  [5/9/2014 pseudonym]

	// 2. Get Params Buf size [5/19/2013 Pseudonym]
	unsigned int nParamsBufSize = 0;
	ParseData(pStart, PARAMCOUNT_OFFSET + 0x0c, 4, (char*)&nParamsBufSize);

	if(nBufLength < PARAMBLK_OFFSET + nParamCount * 16 + nParamsBufSize)
		return RETURN_STATUS::RETURN_NEEDMOREDATA;

	// 3. return [5/19/2013 Pseudonym]
	pEnd = (char*)(pStart + PARAMBLK_OFFSET + 16*nParamCount + nParamsBufSize);

	// 4. return 0, if done successfully [5/8/2013 Pseudonym]
	return RETURN_STATUS::RETURN_OK;

#if 0
	if(nBufLength < PARAMBLK_OFFSET + nParamCount * 16)
		return RETURN_STATUS::RETURN_NEEDMOREDATA;

	//////////////////////////////////////////////////////////////////////////
	// 1.1 So disgust, due to the ni spy file format for ibwrt[5/8/2013 Pseudonym]
	//     the wrtbuf length may be not correct as other index-length pairs
	bool isibwrt = false;
	if(nParamCount == 0x05)
	{
		unsigned int nFuncid = 0;
		ParseData(pStart, FUNCID_OFFSET, 4, (char*)&nFuncid);
		if(nFuncid == 0x2B)// Yes, that's TRUE, the NI spy is 2B [5/8/2013 Pseudonym]
		{
			isibwrt = true;
			if(nBufLength < PARAMBLK_OFFSET + 0x60)
				return RETURN_STATUS::RETURN_NEEDMOREDATA;
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// 2. find the maximum offset + length value of the params  [5/8/2013 Pseudonym]
	unsigned int nTotalLength = 0;
	for(unsigned int i = 0; i < nParamCount;i++)
	{
		unsigned short nOffset = 0;
		unsigned int nLength = 0;

		ParseData(pStart, PARAMBLK_OFFSET + 16*i + 1, 2, (char*)&nOffset);
		if(isibwrt == false)
			ParseData(pStart, PARAMBLK_OFFSET + 16*i + 12, 4, (char*)&nLength);
		else{
			// this is ibwrt, the wrtbuf length may be not correct  [5/8/2013 Pseudonym]
			// so, I use the value of count (write count) [5/8/2013 Pseudonym]
			unsigned int ntemp = 4;
			ParseFuncParam(pStart,0x04,(char*)&nLength, ntemp);
			if(ntemp == 0)
				return RETURN_STATUS::RETURN_ERROR;
		}

		if(nTotalLength < nLength + nOffset)
			nTotalLength = nLength + nOffset;
	}
	
	// 3. let pEnd point to the end of IN-Buffer [5/8/2013 Pseudonym]
	if(nBufLength < PARAMBLK_OFFSET + 16*nParamCount + nTotalLength)
		return RETURN_STATUS::RETURN_NEEDMOREDATA;
	pEnd = (char*)(pStart + PARAMBLK_OFFSET + 16*nParamCount + nTotalLength);

	// 4. return 0, if done successfully [5/8/2013 Pseudonym]
	return RETURN_STATUS::RETURN_OK;
#endif
}

/************************************************************************/
/* blocktype_parser                                                     */
/************************************************************************/
/* I assume that the pBlkBase has at least 16 bytes
 *	The caller should ensure that.
 */
int blocktype_parser::GetBlockType(const char* IN pBlkBase, blocktype& blktype)
{
	unsigned int low = 0;
	unsigned int high = 0;
	ParseData(pBlkBase, 0, 4, (char*)&low);
	ParseData(pBlkBase, 4, 4, (char*)&high);

	blktype.setValue(low, high);

	return RETURN_STATUS::RETURN_OK;
}

/************************************************************************/
/* functime_parser                                                      */
/************************************************************************/
int functime_parser ::GetTime(const char* IN pBase, SYSTEMTIME& theTime)
{
	memset(&theTime, 0, sizeof(SYSTEMTIME));
	ParseData(pBase, TIME_OFFSET, 1, (char*)&theTime.wHour);
	ParseData(pBase, TIME_OFFSET+1, 1, (char*)&theTime.wMinute);
	ParseData(pBase, TIME_OFFSET+2, 1, (char*)&theTime.wSecond);
	ParseData(pBase, TIME_OFFSET+3, 2, (char*)&theTime.wMilliseconds);
	
	return RETURN_STATUS::RETURN_OK;
}

int functime_parser::Getvalue(const char* IN pBase,std::string& strValue)
{
	SYSTEMTIME theTime;
	int nret = GetTime(pBase,theTime);
	if(nret != RETURN_STATUS::RETURN_OK)
		return nret;
	std::ostringstream s;
	s << std::setw(2) << std::setfill('0') << theTime.wHour <<':' <<std::setw(2) << std::setfill('0')<< theTime.wMinute <<':'<<std::setw(2) << std::setfill('0')<<theTime.wSecond<<'.'<< std::setw(3) << std::setfill('0') << theTime.wMilliseconds;
	strValue = s.str();

	return RETURN_STATUS::RETURN_OK;
}

/************************************************************************/
/*  paramcount_parser                                                   */
/************************************************************************/
int paramcount_parser::Getvalue(const char* IN pBase,std::string& strValue)
{
	unsigned int nCount = 0;
	int nret = GetParamCount(pBase,nCount);
	if(nret != RETURN_STATUS::RETURN_OK)
		return nret;

	std::ostringstream s;
	s << nCount;
	strValue = s.str();

	return RETURN_STATUS::RETURN_OK;
}
int paramcount_parser::GetParamCount(const char* IN pBase, unsigned int& value)
{
	ParseData(pBase, PARAMCOUNT_OFFSET, 1, (char*)&value);// only One byte is used to store param cnt  [5/9/2014 pseudonym]
	
	return RETURN_STATUS::RETURN_OK;
}

/************************************************************************/
/*  funcid_parser                                                       */
/************************************************************************/
int funcid_parser::GetFuncId(const char* IN pBase, unsigned int& value)
{
	ParseData(pBase, FUNCID_OFFSET, 4, (char*)&value);

	return RETURN_STATUS::RETURN_OK;
}

/************************************************************************/
/* funcNestedParam_parser                                               */
/************************************************************************/
funcNestedParam_parser::funcNestedParam_parser(const std::string& name, int nIndex,int type )
	:paramName_(name),
	paramIndex_(nIndex),
	type_(type)
{
}

int funcNestedParam_parser::Getvalue(const char* IN pBase,std::string& strValue)
{
	const static unsigned int BUFFER_LENGTH = 128;
	unsigned int nLength = BUFFER_LENGTH;
	unsigned char pValue[BUFFER_LENGTH];
	memset(pValue, 0, BUFFER_LENGTH);

	unsigned int nParamIndex = (unsigned int)paramIndex_;
	// 1. if the paramIndex_ == -1
	if(paramIndex_ == -1)
	{
		// 1.1 get the param count [5/30/2013 Pseudonym]
		unsigned int nparamCount = 0;
		ParseData(pBase, PARAMCOUNT_OFFSET, 1, (char*)&nparamCount);// only One byte is used to store param cnt  [5/9/2014 pseudonym]

		// 1.2. let paramIndexReal = param_count -1 [5/30/2013 Pseudonym]
		nParamIndex = nparamCount - 1;
	}

	// 2. Get the specified Index value [5/30/2013 Pseudonym]
	ParseFuncParam(pBase, nParamIndex, (char*)pValue,nLength);
	if(nLength == 0)
		return RETURN_STATUS::RETURN_ERROR;

	std::ostringstream s;
	if(type_ == VALUETYPE_INT)
	{
		s << "0x" << std::hex <<std::setw(8)<<std::setfill('0')<<*((unsigned int*)pValue);
	}
	else
	{
		s << (char*)pValue;
	}
	strValue = s.str();

	return RETURN_STATUS::RETURN_OK;
}

/************************************************************************/
/* rbuf_parser                                                          */
/************************************************************************/
int wrtbuf_parser::Getvalue(const char* IN pBase,std::string& strValue)
{
	// 0. get param count to verify [5/8/2013 Pseudonym]
	unsigned int nparamCount = 0;
	ParseData(pBase, PARAMCOUNT_OFFSET, 1, (char*)&nparamCount);// only One byte is used to store param cnt  [5/9/2014 pseudonym]
	if(nparamCount < 5)
		return RETURN_STATUS::RETURN_ERROR;

	// 1. get wrtBuf offset, 3rd param, 0-Indexed [5/8/2013 Pseudonym]
	unsigned short noffset = 0;
	ParseData(pBase, PARAMBLK_OFFSET + 3 * 16 + 1, 2, (char*)&noffset);

	// 2. get wrtBuf length, 4th param value, 0-Indexed [5/8/2013 Pseudonym]
	unsigned int nwrtBufLength = 0;
	unsigned int nLength = 4;

	ParseFuncParam(pBase, 4, (char*)&nwrtBufLength, nLength);
	if(nLength == 0 || nwrtBufLength == 0)
		return RETURN_STATUS::RETURN_ERROR;

	// 3. copy wrfbuf value to my buffer[5/8/2013 Pseudonym]
	char* pwrtbuf = new char[nwrtBufLength + 1];
	memset(pwrtbuf, 0, nwrtBufLength + 1);

	ParseData(pBase, PARAMBLK_OFFSET + noffset + nparamCount * 16, nwrtBufLength, (char*)pwrtbuf);

	strValue = std::string(pwrtbuf);

	delete[] pwrtbuf;
	return RETURN_STATUS::RETURN_OK;

}


/************************************************************************/
/*  rbuf_parser                                                         */
/************************************************************************/
int rbuf_parser::Getvalue(const char* IN pBase,std::string& strValue)
{
	unsigned int nrdbufLength = 0;
	unsigned int nLength = 4;
	// 1. get rdbuf length [5/8/2013 Pseudonym]
	ParseFuncParam(pBase, 5, (char*)&nrdbufLength, nLength);
	if(nLength == 0)
		return RETURN_STATUS::RETURN_ERROR;

	// 2. get rdbuf content [5/8/2013 Pseudonym]
	char* pValue = new char[nrdbufLength + 1];
	memset(pValue,0,nrdbufLength + 1);
	nLength = nrdbufLength;

	ParseFuncParam(pBase, 4, (char*)pValue, nLength);

	int nret = RETURN_STATUS::RETURN_ERROR;
	if(nLength == 0)
	{
		nret = RETURN_STATUS::RETURN_ERROR;
	}
	else
	{
		nret = RETURN_STATUS::RETURN_OK;
		strValue = pValue;
	}
	delete[] pValue;

	return nret;
}

/************************************************************************/
/* funcIOBufNestedParam_parser                                          */
/*  may not applicable for viWrite and viread                           */
/************************************************************************/
funcIOBufNestedParam_parser ::funcIOBufNestedParam_parser(const std::string& name, unsigned int nIndex)
	:paramName_(name),
	paramIndex_(nIndex)
{

}

int funcIOBufNestedParam_parser ::Getvalue(const char* IN pStart,std::string& strValue)
{
	// 1. get param count [5/19/2013 Pseudonym]
	unsigned int nParamCount = 0;
	ParseData(pStart, PARAMCOUNT_OFFSET, 1, (char*)&nParamCount);// only One byte is used to store param cnt  [5/9/2014 pseudonym]

	// 2. Get Params Buf size [5/19/2013 Pseudonym]
	unsigned int nParamsBufSize = 0;
	ParseData(pStart, PARAMCOUNT_OFFSET + 0x0c, 4, (char*)&nParamsBufSize);

	// 3. calc total buf excluding the nIndex param  [5/19/2013 Pseudonym]
	unsigned int nOthersBuflength = 0;
	for(int i = 0; i < nParamCount; i++)
	{
		if(i == paramIndex_)
			continue;
		unsigned int nLength = 0;		
		ParseData(pStart, PARAMBLK_OFFSET + i * 16 + 12, 4, (char*)&nLength);
		nOthersBuflength += nLength;
	}

	// 4. calc the real buf length of the Index param [5/19/2013 Pseudonym]
	unsigned short nThisParamLength = nParamsBufSize - nOthersBuflength;		

	// 5. get that param value [5/19/2013 Pseudonym]
	unsigned short noffset = 0;		
	ParseData(pStart, PARAMBLK_OFFSET + paramIndex_ * 16 + 1, 2, (char*)&noffset);

	char* pvalue = new char[nThisParamLength + 1];
	memset(pvalue, 0, nThisParamLength + 1);

	ParseData(pStart, PARAMBLK_OFFSET + noffset + nParamCount * 16, nThisParamLength, pvalue);

	strValue = std::string(pvalue);

	delete[] pvalue;
	return RETURN_STATUS::RETURN_OK;
}

/************************************************************************/
/*                                                                      */
/************************************************************************/
condition::condition(const std::vector<unsigned int>& devid)
	:devidparser_("devid",0,funcNestedParam_parser::VALUETYPE_INT),
	devids_(devid)
{

}
bool condition ::operator()(const char* pInBufStart, const char* pOutBufStart,  funcNestedParam_parser* pDevParser/*= NULL*/) const
{
	std::string strdevid;
	if (pDevParser == NULL)
	{
		pDevParser = (funcNestedParam_parser*)&devidparser_;
	}
	if(pDevParser->Getvalue(pInBufStart,strdevid) == RETURN_STATUS::RETURN_ERROR)
		return false;

	unsigned long int ul = strtoul(strdevid.c_str(),NULL,0); 
	if(std::find(devids_.begin(),devids_.end(),ul) != devids_.end())
		return true;

	return false;
}

